//
// Created on 2023/6/7.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef VideoEncoder_H
#define VideoEncoder_H
#include <ctype.h>
#include <memory>
#include <multimedia/av_codec/native_avcodec_videoencoder.h>
#include <multimedia/av_codec/native_avformat.h>
#include <multimedia/av_codec/native_avmemory.h>
#include <mutex>
#include <queue>
#include <string>
#include <map>
#include <thread>
namespace OHOS {
namespace Media {



struct AvFormat {
    std::string codec_mime = "";
    int32_t width = -1;
    int32_t height = -1;
    int32_t pixel_format = -1;
    int32_t frame_rate = -1;
    int32_t bitrate = -1;
    int32_t video_encode_bitrate_mode = -1;
    int32_t i_frame_interval = -1;
    int32_t codec_profile = -1;
    int32_t codec_quality = -1;
};

class AVCodecCallback {
public:
    virtual ~AVCodecCallback() = default;
    virtual void OnCodecError(int32_t errorCode) = 0;
    virtual void OnOutputFormatChanged(AvFormat* format) = 0;
    virtual void OnInputBufferAvailable(uint8_t* data, int32_t size) = 0;
    virtual void OnOutputBufferAvailable(uint8_t* data,int32_t size,int32_t pts,uint32_t flags) = 0;
};
class VideoEncoder{
public:
    VideoEncoder(std::string mime);
    ~VideoEncoder();
    int32_t configure(AvFormat* avFormat);
    int32_t prepare();
    int32_t start();
    int32_t stop();
    int32_t flush();
    int32_t rest();
    std::string getOutputDescription();
    int32_t sendFrameData(uint8_t* data,int32_t size,int32_t timestamp);
    int32_t release();
    void SetCallback(std::shared_ptr<AVCodecCallback> cb);
private:
    static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData);
    static void OnStreamChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData);
    static void OnNeedInputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data, void *userData);
    static void OnNewOutputData(OH_AVCodec *codec, uint32_t index, OH_AVMemory *data,
            OH_AVCodecBufferAttr *attr, void *userData);
    static OH_AVFormat* convertAvFormatToOHFormat(AvFormat* avFormat);
    static AvFormat* convertOHFormatToAvFormat(OH_AVFormat* format);
    static VideoEncoder* GetVideoEncoder(OH_AVCodec *codec);
    static void setVideoEncoderMap(OH_AVCodec* codec,VideoEncoder* encoder);
    static void delVideoEncoderMap(OH_AVCodec* codec);
    int32_t setEncoderCallback();
    void pushInputBufferToQueue(int32_t index,OH_AVMemory* buffer);
    std::queue<uint32_t> indexQueue;
    std::queue<OH_AVMemory*> inBufferQueue;
    OH_AVCodec* venc_ = nullptr;
    static std::mutex mutex_;
    static std::map<OH_AVCodec*, VideoEncoder*> encoderMap_;
    std::shared_ptr<AVCodecCallback> avcodecCb = nullptr;
    std::mutex queueMutex_;
    
    
};
class VideoEncoderFactory {
public:
    static std::shared_ptr<VideoEncoder> CreateByMime(const std::string mime);
};

} // namespace Media
} // namespace OHOS
#endif //VideoEncoder_H
